home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / ddj0897.zip / RCSC.ZIP / LIB51 / KERNEL.C < prev    next >
C/C++ Source or Header  |  1997-01-12  |  17KB  |  859 lines

  1. /*
  2. ** Concurrent Small C Multi-tasking Kernel for the 8051
  3. ** Copyright 1997 Andy W. K. Yuen
  4. ** All rights reserved.
  5. **
  6. ** Please note that for efficiency reasons, the kernel is
  7. ** significantly different from the 80x86 version.
  8. ** However, the overall architecture remains unchanged.
  9. */
  10. #include <stdio.h>
  11.  
  12. /* common data types */
  13. #define UINT        unsigned int
  14. #define UCHAR        unsigned char
  15.  
  16. /* processor-dependent implementation: 8051 version */
  17. #define MAXINTR        12
  18. #define TIMERINTR    1
  19. #define SERIALINTR    4
  20.  
  21. /* task descriptor structure and constants */
  22. #define TD_NEXT         0    /* points to next descriptor */
  23. #define TD_PRIOR        1    /* task priority */
  24. #define TD_DELTA    2    /* delta value for Delay */
  25. #define TD_HSP        3    /* hardware stack pointer */
  26. #define TD_CONTEXT    4    /* start of task context */
  27. #define TD_SP           TD_CONTEXT+4    /* task's stack pointer */
  28. #define TD_BP        TD_CONTEXT+5    /* task base pointer */
  29. #define TD_STKAREA    TD_CONTEXT+12    /* hardware stack area */
  30.  
  31. #define TD_SIZE         (32 * sizeof(int))    /* task descriptor size */
  32.  
  33. #define PRIOR           64    /* default task priority */
  34. #define FLAGS           0x10    /* initial flag register value: use bank 2 */
  35.  
  36. #define BUFSIZE        128    /* read/write buffer size */
  37.  
  38. /* part of the interrupt descriptor has been moved to code segment */
  39. static UINT intrcond[MAXINTR];    /* interrupt condition variable */
  40. static UINT intrerror[MAXINTR];    /* interrupt error variable */
  41.  
  42. /* kernel linked lists */
  43. static UINT *running;    /* running task */
  44. static UINT *runcopy;    /* copy of running task descriptor */
  45. static UINT *ready;    /* ready task list */
  46. static UINT *delta;    /* delta list for time delay processing */
  47.  
  48. /* serial comm monitor variables */
  49. static UCHAR *readbuf;            /* read buffer */
  50. static UCHAR *writebuf;            /* write buffer */
  51. static UINT readhead, readtail, readerror;
  52. static UINT writehead, writetail, writeerror;
  53. static CONDITION readwait;
  54. static CONDITION writewait;
  55.  
  56. /* *******************************************************
  57.     start of general kernel functions 
  58. ******************************************************** */
  59.  
  60. /* wait on condition: used inside a monitor */
  61. void Wait(cond)
  62. UINT *cond;
  63. {
  64.     runcopy = running;
  65.     _Insert(cond, running);
  66.  
  67.     running = ready;
  68.     ready = running[TD_NEXT];
  69.     _Transfer();
  70. }
  71.  
  72.  
  73. /* signal condition: used inside a monitor */
  74. void Signal(cond)
  75. UINT *cond;
  76. {
  77.     if (*cond)
  78.         {
  79.         runcopy = running;
  80.         _Insert(&ready, running);
  81.  
  82.         running = *cond;
  83.         *cond = running[TD_NEXT];
  84.         _Transfer();
  85.         }
  86. }
  87.  
  88.  
  89. /* put running task in ready queue and dispatch first one in ready queue */
  90. void Yield()
  91. {
  92.     disable();
  93.     if (ready)
  94.         _Preempt(&ready);
  95.     enable();
  96. }
  97.  
  98.  
  99. /* delay for the specified number of ticks */
  100. Delay(ticks)
  101. UINT ticks;
  102. {
  103.     UINT *last, *current;
  104.  
  105.     if (ticks <= 0)
  106.         return 0;
  107.  
  108.     disable();
  109.  
  110.     /* insert into delta list */
  111.     last = 0; current = delta;
  112.     while ((current) && (ticks >= current[TD_DELTA]))
  113.     {
  114.         last = current;
  115.         current = current[TD_NEXT];
  116.         ticks -= last[TD_DELTA];
  117.     }
  118.  
  119.     running[TD_NEXT] = current;
  120.     running[TD_DELTA] = ticks;
  121.  
  122.     if (last)
  123.         last[TD_NEXT] = running;
  124.     else
  125.         delta = running;
  126.  
  127.     _Preempt(NULL);
  128.  
  129.     enable();
  130.  
  131.     return 0;
  132. }
  133.  
  134.  
  135. /* initiate i/o operation and make requesting task wait in interrupt 
  136.     condition variable. Return -1 in retcode if no such interrupt 
  137.     number in interrupt list */
  138. void StartIO(intrnum, fn, retcode)
  139. UINT intrnum; int (*fn)(); int *retcode;
  140. {
  141.     UINT *entry;
  142.     UINT errcode;
  143.  
  144.     disable();
  145.  
  146.     /* initiate i/o operation and wait */
  147.     if (intrnum <= MAXINTR) {
  148.         if (fn) {
  149.             if ((errcode = (*fn)()) == 0) {
  150.                 Wait(&intrcond[intrnum]);
  151.                 }
  152.             else {
  153.                 intrerror[intrnum] = errcode;
  154.                 }
  155.             }
  156.         else
  157.             Wait(&intrcond[intrnum]);
  158.  
  159.         *retcode = intrerror[intrnum];
  160.         }
  161.     else
  162.         *retcode = -1;
  163.  
  164.     enable();
  165. }
  166.  
  167. /* get the priority of running task */
  168. GetPrior()
  169. {
  170.     return running[TD_PRIOR];
  171. }
  172.  
  173. /* set the priority of running task */
  174. void SetPrior(prior)
  175. UINT prior;
  176. {
  177.     running[TD_PRIOR] = prior;
  178. }
  179.  
  180. /* get a byte from input port */
  181. inpbyte(port)
  182. UINT port;
  183. {
  184. #asm
  185.     GETw1s(4)
  186.     MOV    A,V1L
  187.     MOV    R0,A
  188.     MOV    A,@R0
  189.     MOV    V1L,A
  190.     MOV    V1H,#0
  191. #endasm
  192. }
  193.  
  194. /* write a byte to output port */
  195. void outpbyte(port, value)
  196. UINT port; int value;
  197. {
  198. #asm
  199.     GETw1s(6)
  200.     MOV    A,V1L
  201.     MOV    R0,A
  202.     GETw1s(4)
  203.     MOV    A,V1L
  204.     MOV    @R0,A
  205. #endasm
  206. }
  207.  
  208. /* disable interrupt */
  209. void disable()
  210. {
  211. #asm
  212.     CLR    EA
  213. #endasm
  214. }
  215.  
  216.  
  217. /* enable interrupt */
  218. void enable()
  219. {
  220. #asm
  221.     SETB    EA
  222. #endasm
  223. }
  224.  
  225. /* *******************************************************
  226.     start of internal kernel functions 
  227. ******************************************************** */
  228.  
  229. /* insert task descriptor into specified queue according to priority.
  230.     The larger the priority value, the higher the priority. */
  231. void _Insert(queue, td)
  232. UINT *queue; UINT *td;
  233. {
  234.     UINT *last, *current;
  235.  
  236.     last = 0; current = *queue;
  237.     while ((current) && (current[TD_PRIOR] >= td[TD_PRIOR]))
  238.     {
  239.         last = current;
  240.         current = current[TD_NEXT];
  241.     }
  242.  
  243.     td[TD_NEXT] = current;
  244.  
  245.     if (last)
  246.         last[TD_NEXT] = td;
  247.     else
  248.         *queue = td;
  249. }
  250.  
  251. /* move the running task to toq and dispatch first task from ready */
  252. void _Preempt(toq)
  253. UINT *toq;
  254. {
  255.     runcopy = running;
  256.     if (toq)
  257.         _Insert(toq, running);
  258.  
  259.     running = ready;
  260.     ready = running[TD_NEXT];
  261.     _Transfer();
  262. }
  263.  
  264. /* process delta list and move delayed tasks to ready queue if it is time */
  265. interrupt _dodelta(TIMERINTR)
  266. {
  267.     if (delta)
  268.         {
  269.         if (!--delta[TD_DELTA])
  270.             {
  271.             UINT *current;
  272.             UINT *last;
  273.  
  274.             current = delta;
  275.             while ((current) && (!current[TD_DELTA]))
  276.                 {
  277.                 last = current;
  278.                 current = current[TD_NEXT];
  279.                 _Insert(&ready, last);
  280.                 }
  281.             delta = current;
  282.             }
  283.         }
  284.  
  285.     /* return 1 to inform common ISR to do task switch */
  286.     return 1;
  287. }
  288.  
  289. extern UINT _stksize;
  290.  
  291. /* create a new task */
  292. void _Task(fn, priority, stacksize)
  293. UINT fn; UINT priority; UINT stacksize;
  294. {
  295.     UINT *block;
  296.     UINT *ptr;
  297.     UINT size;
  298.  
  299.     /* allocate task descriptor */
  300.     block = calloc(1, TD_SIZE);
  301.     block[TD_PRIOR] = (priority)? priority: PRIOR;
  302.  
  303.     /* allocate stack for task */
  304.     size = (stacksize)? stacksize: _stksize;
  305.     ptr = calloc(1, size);
  306.  
  307.     /* set up hardware and software stacks */
  308.     block[TD_HSP] = 0x2a;
  309.     block[TD_SP] = block[TD_BP] = ptr;
  310.  
  311.     /* setup fn start address and PSW */
  312.     block[TD_STKAREA] = (fn / 256) + (fn * 256);
  313.     block[TD_STKAREA + 1] = FLAGS * 256;
  314.  
  315.     _Insert(&ready, block);
  316. }
  317.  
  318.  
  319. /* system idle task */
  320. void _Idle()
  321. {
  322.     while (1)
  323.     {
  324.  
  325. /* It does not matter whether Idle calls Yield() or not. User and timer
  326.     interrupts will do the job of task switching.
  327.         Yield();
  328. */
  329.     }
  330. }
  331.  
  332.  
  333. /* start multi-tasking by converting caller usually main() into a task 
  334.     and perform a task switch */
  335. void _Go()
  336. {
  337.     UINT *block;
  338.  
  339.     /* create idle task */
  340.     _Task(_Idle, 1, NULL);
  341.  
  342.     /* make caller into the running task */
  343.     block = calloc(1, TD_SIZE);
  344.     block[TD_PRIOR] = PRIOR;
  345.     running = block;
  346.  
  347.     /* initialize timer and serial communication */
  348.     _InitHardware();
  349.  
  350.     /* start multi-tasking */
  351. }
  352.  
  353. /* called from handler to check error code */
  354. void _checkerr(error, intnum)
  355. UINT error; UINT intnum;
  356. {
  357.     /* if user function return non-zero, it is time to wake up
  358.         task waiting on this interrupt, if one is waiting */
  359.     intrerror[intnum] = error;
  360.     if (error && intrcond[intnum]) {
  361.         if (intnum != TIMERINTR) {
  362.             runcopy = intrcond[intnum];
  363.             intrcond[intnum] = runcopy[TD_NEXT];
  364.             _Insert(&ready, runcopy);
  365.             }
  366.  
  367.         /* save task context */
  368.         if (ready) {
  369.             runcopy = running;
  370.             _Insert(&ready, running);
  371.             running = ready;
  372.             ready = running[TD_NEXT];
  373.  
  374.             }
  375.  
  376.         }
  377. }
  378.  
  379. /* commom interrupt handler. Every user-handled interrupt jumps here first */
  380. #asm
  381. __handler:
  382.     CLR    EA        ;;disable interrupts
  383.     MOV    CDPL,DPL    ;;save context of running task
  384.     MOV    CDPH,DPH
  385.     MOV    CP2,P2
  386.     MOV    CA,A
  387.     MOV    CB,B
  388.     POP    10        ;;remove user function return address
  389.     POP    9
  390.     PUSH    PSW        ;;save PSW
  391.  
  392.     MOV    PSW,#0        ;;switch to register bank 0
  393.     GETw1m(_running)
  394.     ADD1n(7)
  395.     MOV    DPL,V1L
  396.     MOV    DPH,V1H
  397.     MOV    A,SP        ;;save hardware stack pointer
  398.     MOVX    @DPTR,A
  399.     INC    DPTR
  400.     MOV    R0,#10h
  401.  
  402. __handler_savecontext:
  403.     MOV    A,@R0        ;;save context
  404.     MOVX    @DPTR,A
  405.     INC    DPTR
  406.     MOV    A,R0
  407.     INC    R0
  408.     CJNE    A,SP,__handler_savecontext
  409.  
  410.     MOV    DPH,10        ;;duplicate return address
  411.     MOV    DPL,9
  412.     CLR    A
  413.     MOVC    A,@A+DPTR
  414.     MOV    V1H,A
  415.     MOV    A,#1
  416.     MOVC    A,@A+DPTR
  417.     MOV    V1L,A
  418.     CALL1            ;;invoke user interrupt function
  419.     PUSH1
  420.  
  421.     MOV    DPH,10
  422.     MOV    DPL,9
  423.     MOV    A,#2
  424.     MOVC    A,@A+DPTR    ;;get interrupt number
  425.     MOV    V1H,A
  426.     MOV    A,#3
  427.     MOVC    A,@A+DPTR
  428.     MOV    V1L,A
  429.     PUSH1
  430.     ARGCNTn(2)
  431.     LCALL    __checker    ;;check user function error code
  432.     ADDSP(4)
  433.  
  434.     ;;restore context of task to run next
  435.     GETw1m(_running)
  436.     ADD1n(7)
  437.     MOV    DPL,V1L
  438.     MOV    DPH,V1H
  439.     MOVX    A,@DPTR
  440.     MOV    SP,A        ;;restore hardware stack pointer
  441.     INC    DPTR
  442.     MOV    R0,#10h
  443. __handler_restorecontext:
  444.     MOVX    A,@DPTR        ;;restore context
  445.     MOV    @R0,A
  446.     INC    DPTR
  447.     MOV    A,R0
  448.     INC    R0
  449.     CJNE    A,SP,__handler_restorecontext
  450.  
  451.     MOV    DPL,CDPL
  452.     MOV    DPH,CDPH
  453.     MOV    P2,CP2
  454.     MOV    A,CA
  455.     MOV    B,CB
  456.     POP    PSW        ;;restore PSW
  457.     SETB    EA        ;;enable interupts
  458.     RETI
  459. #endasm
  460.  
  461. /* concurrent Small C initialization: monitor initialization, 
  462.     task declaration, interrupt handler setup, convert main 
  463.     into a task and start multi-tasking */
  464. void _cscinit ()
  465. {
  466.  
  467. #asm
  468.     ;;scan monitor table for entries and call each function
  469.     MOV    8,#mon_size / 3
  470.     CLR    A
  471.     ORL    A,8
  472.     JZ    __scantask
  473.     MOV    DPTR,#mon_start
  474. __nextmon:
  475.     ;;save DPTR
  476.     MOV    9,DPH
  477.     MOV    10,DPL
  478.     ;;set up return address
  479.     MOV    DPTR,#__monresume
  480.     PUSH    DPL
  481.     PUSH    DPH
  482.     MOV    DPH,9
  483.     MOV    DPL,10
  484.     CLR    A
  485.     JMP    @A+DPTR
  486. __monresume:
  487.     ;;restore DPTR
  488.     MOV    DPH,9
  489.     MOV    DPL,10
  490.     INC    DPTR
  491.     INC    DPTR
  492.     INC    DPTR
  493.     DJNZ    8,__nextmon
  494.  
  495. __scantask:
  496.     ;;scan task table for entries and create task
  497.     MOV    8,#task_size / 6
  498.     CLR    A
  499.     ORL    A,8
  500.     JZ    __taskdone
  501.     MOV    DPTR,#task_start
  502. __nexttask:
  503.     ;;save DPTR
  504.     MOV    9,DPH
  505.     MOV    10,DPL
  506.     ;;set up parameters for task creation
  507.     CLR    A
  508.     MOVC    A,@A+DPTR
  509.     MOV    V1H,A
  510.     MOV    A,#1
  511.     MOVC    A,@A+DPTR
  512.     MOV    V1L,A
  513.     PUSH1
  514.     MOV    A,#2
  515.     MOVC    A,@A+DPTR
  516.     MOV    V1H,A
  517.     MOV    A,#3
  518.     MOVC    A,@A+DPTR
  519.     MOV    V1L,A
  520.     PUSH1
  521.     MOV    A,#4
  522.     MOVC    A,@A+DPTR
  523.     MOV    V1H,A
  524.     MOV    A,#5
  525.     MOVC    A,@A+DPTR
  526.     MOV    V1L,A
  527.     PUSH1
  528.     ARGCNTn(3)
  529.     LCALL    __Task
  530.     ADDSP(6)
  531.  
  532.     ;;restore DPTR
  533.     MOV    DPH,9
  534.     MOV    DPL,10
  535.     INC    DPTR
  536.     INC    DPTR
  537.     INC    DPTR
  538.     INC    DPTR
  539.     INC    DPTR
  540.     INC    DPTR
  541.     DJNZ    8,__nexttask
  542.  
  543. __taskdone:
  544. #endasm
  545.  
  546.     /* set up timer condition variable*/
  547.     intrcond[TIMERINTR] = ready;
  548.  
  549.     /* setup timers and serial comm for multi-tasking */
  550.     _Go();
  551.  
  552. }
  553.  
  554. /* initialize hardware facilitites: timere and serial comm. */
  555. void _InitHardware()
  556. {
  557. #asm
  558.     ;;timer0 periodic interrupt used for multitasking
  559.     ;;and timer1 used as baud rate generator for serial comm
  560.     MOV    TMOD,#21h
  561.     MOV    TCON,#55h
  562.     MOV    TH1,#0f3h    ;;2400 baud
  563.     MOV    SCON,#50h    ;;serial comm mode 1, 8 data bits
  564.     MOV    IE,#92h        ;;enable interrupts
  565. #endasm
  566. }
  567.  
  568.  
  569. /* switch from the task whose descriptor is in runcopy to that in running.
  570.     runcopy and running have been set up by caller.
  571.     Interrupts have been disabled before it gets here */
  572. #asm
  573. public __Transfe:
  574.     MOV    CDPL,DPL    ;;save context of running task
  575.     MOV    CDPH,DPH
  576.     MOV    CP2,P2
  577.     MOV    CA,A
  578.     MOV    CB,B
  579.     PUSH    PSW        ;;save PSW
  580.  
  581.     MOV    PSW,#0        ;;switch to register bank 0
  582.     GETw1m(_runcopy)
  583.     ADD1n(7)
  584.     MOV    DPL,V1L
  585.     MOV    DPH,V1H
  586.     MOV    A,SP        ;;save hardware stack pointer
  587.     MOVX    @DPTR,A
  588.     INC    DPTR
  589.     MOV    R0,#10h
  590. __savecontext:
  591.     MOV    A,@R0        ;;save context
  592.     MOVX    @DPTR,A
  593.     INC    DPTR
  594.     MOV    A,R0
  595.     INC    R0
  596.     CJNE    A,SP,__savecontext
  597.  
  598.     ;;restore context of task to run next
  599.     GETw1m(_running)
  600.     ADD1n(7)
  601.     MOV    DPL,V1L
  602.     MOV    DPH,V1H
  603.     MOVX    A,@DPTR
  604.     MOV    SP,A        ;;restore hardware stack pointer
  605.     INC    DPTR
  606.     MOV    R0,#10h
  607. __restorecontext:
  608.     MOVX    A,@DPTR        ;;restore context
  609.     MOV    @R0,A
  610.     INC    DPTR
  611.     MOV    A,R0
  612.     INC    R0
  613.     CJNE    A,SP,__restorecontext
  614.  
  615.     MOV    DPL,CDPL
  616.     MOV    DPH,CDPH
  617.     MOV    P2,CP2
  618.     MOV    A,CA
  619.     MOV    B,CB
  620.     POP    PSW        ;;restore PSW
  621.     RETI
  622.  
  623. #endasm
  624.  
  625. /* *******************************************************
  626.     start of kernel serial comm monitor 
  627. ******************************************************** */
  628. void monitor serial()
  629. {
  630.     /* allocate memory for buffers */
  631.     readbuf = calloc(1, BUFSIZE);
  632.     writebuf = calloc(1, BUFSIZE);
  633. }
  634.  
  635. /* write a char, suspend execution if write buffer is full */
  636. entry putchar(ch)
  637. UINT ch;
  638. {
  639. UINT index;
  640.  
  641.     if ((index = (writetail + 1) % BUFSIZE) == writehead) {
  642.         /* buffer full */
  643.         Wait(&writewait);
  644.         }
  645.  
  646.     if (writetail == writehead) {
  647.         /* buffer empty, send character */
  648.         return _xmit(ch);
  649.         }
  650.     else {
  651.         /* store in circular buffer */
  652.         writetail = index;
  653.         writebuf[writetail] = ch;
  654.         }
  655.  
  656.     return ch;
  657. }
  658.  
  659. /* read a char, suspend execution if read buffer is empty */
  660. entry getchar()
  661. {
  662. UINT ch;
  663.  
  664.     if (readtail == readhead) {
  665.         /* buffer empty */
  666.         Wait(&readwait);
  667.         }
  668.  
  669.     /* store in circular buffer */
  670.     ch = readbuf[readhead];
  671.     readhead = (readhead + 1) % BUFSIZE;
  672.     return ch;
  673. }
  674.  
  675. /* interrupt service routine for serial comm */
  676. interrupt _serialisr(SERIALINTR)
  677. {
  678. #asm
  679.     JNB    RI,__chkxmit
  680.     ;;get char from serial port
  681.     MOV    A,SBUF
  682.     CLR    RI
  683.     MOV    V1L,A
  684.     CLR    A
  685.     MOV    V1H,A
  686.     PUSH1
  687.     ARGCNTn(1)
  688.     LCALL    __putread    ;;put in circular buffer
  689.     ADDSP(2)
  690. __chkxmit:
  691.     JNB    TI,__isrdone
  692.     ;;ready to transmit
  693.     CLR    TI
  694.     LCALL    __getwrit    ;;get char from circular buffer
  695.     MOV    A,V1H
  696.     JNB    ACC.7,__isrdone    ;;send only when buffer is not empty
  697.     MOV    A,V1L
  698.     MOV    SBUF,A
  699. __isrdone:
  700. #endasm
  701. }
  702.  
  703. /* put char in read circular buffer and wake up waiting process */
  704. _putread(ch)
  705. UCHAR ch;
  706. {
  707. UINT index;
  708.  
  709.     if ((index = (readtail + 1) % BUFSIZE) != readhead) {
  710.         /* store in circular buffer */
  711.         readbuf[index] = ch;
  712.         Signal(&readwait);
  713.         return ch;
  714.         }
  715.  
  716.     /* buffer full */
  717.     return EOF;
  718. }
  719.  
  720. /* get char from write circular buffer and wake up waiting process */
  721. _getwrite()
  722. {
  723. UINT empty, ch;
  724.  
  725.     if (writetail != writehead) {
  726.         /* buffer not empty */
  727.         ch = writebuf[writehead];
  728.         writehead = (writehead + 1) % BUFSIZE;
  729.         Signal(&writewait);
  730.         return ch;
  731.         }
  732.  
  733.     /* buffer empty */
  734.     return EOF;
  735. }
  736.  
  737. /* transmit one char */
  738. _xmit(ch)
  739. UCHAR ch;
  740. {
  741. #asm
  742.     GETw1s(-1)
  743.     MOV    A,V1L
  744.     MOV    SBUF,A
  745. #endasm
  746. }
  747.  
  748. /* *******************************************************
  749.     start of kernel startup code
  750.     Always place at end of module.
  751. ******************************************************** */
  752.  
  753. #asm
  754. ;;startup code
  755. extern code _main
  756.  
  757.  
  758. ;;hardware stack starting address
  759. ISTACK    equ 0x25
  760.  
  761.  
  762. public __startup:
  763.     MOV    IE,#0        ;;disable all interrupts
  764.     MOV    SP,#ISTACK
  765.     MOV    PSW,#10h    ;;use register bank 2
  766.     ACALL    __initvar
  767.     ;;set up software stack according to returned value
  768.     MOV    VSPL,A
  769.     MOV    VSPH,B
  770.     MOV    VBPL,VSPL
  771.     MOV    VBPH,VSPH
  772.     LCALL    _main
  773.     SJMP    __startup    ;;should not get here at all
  774.  
  775. ;;make sure no data variable starts at location 0 because
  776. ;;the NULL pointer is defined as 0
  777. ;;
  778.     
  779.  
  780. __initvar:
  781. ;;copy constants stored in code segment to xdata segment
  782. ;;you should not start the watchdog timer before this is done
  783. ;;if you have no control over this then you have to insert code 
  784. ;;to reset the watchdog timer while copying to avoid reset
  785.  
  786. ;;set up addresses and number of bytes to copy
  787.     MOV    R2,#LOW cvar_size
  788.     MOV    R3,#(HIGH cvar_size) + 1
  789.     MOV    DPTR,#CLITBEG
  790.     MOV    R0,#LOW DVARBEG
  791.     MOV    P2,#HIGH DVARBEG
  792. more:
  793.     DEC    R3
  794. nextbyte:
  795.     MOV    A,#0
  796.     MOVC    A,@A+DPTR
  797.     MOVX    @R0,A
  798.  
  799. ;;increment addresses
  800.     INC    DPTR
  801.     INC    R0
  802.     MOV    A,R0
  803.     JNZ    check
  804.     INC    P2
  805.  
  806. ;;check if done yet
  807. check:
  808.     DEC    R2
  809.     MOV    A,R2
  810.     JZ    check_done
  811.     SJMP    nextbyte
  812. check_done:
  813.     MOV    A,R3
  814.     JNZ    more
  815.  
  816.     ;;finished copying
  817.     ;;initialize system constants:
  818.     ;; __memptr, __memend and __stksize
  819.     MOV    DPTR,#__memptr
  820.     MOV    A,# HIGH (DVARBEG+cvar_size+STKSIZE+6)
  821.     MOVX    @DPTR,A
  822.     INC    DPTR
  823.     MOV    A,# LOW (DVARBEG+cvar_size+STKSIZE+6)
  824.     MOVX    @DPTR,A
  825.     INC    DPTR
  826.     MOV    A,# HIGH (LASTRAM)
  827.     MOVX    @DPTR,A
  828.     INC    DPTR
  829.     MOV    A,# LOW (LASTRAM)
  830.     MOVX    @DPTR,A
  831.     INC    DPTR
  832.     MOV    A,# HIGH (STKSIZE)
  833.     MOVX    @DPTR,A
  834.     INC    DPTR
  835.     MOV    A,# LOW (STKSIZE)
  836.     MOVX    @DPTR,A
  837.     ;;allocate stack area for main()
  838.     MOV    B,# HIGH (DVARBEG+cvar_size+6)
  839.     MOV    A,# LOW (DVARBEG+cvar_size+6)
  840.     RET
  841.  
  842. ;;set cold start vectors
  843.  
  844. VECTOR=32
  845.     SEG CODE AT 0
  846.     LJMP    __startup
  847.  
  848.  
  849. SEG XDATA AT DVARBEG+cvar_size
  850. public __memptr:    ;;free memory pointer
  851.     RW    1
  852. public __memend:    ;;end of free memory
  853.     RW    1
  854. public __stksize:    ;;default stack size
  855.     RW    1
  856.  
  857.  
  858. #endasm
  859.